import typing

from pya2l.parser import A2lParser, MeasurementType, RootNodeType

from . import tool_function
from .datatypes import XCPA2lCharacteristic, XCPA2lMearsurement


class A2lIO(object):
    def __init__(self, a2l_file_path:str) -> None:
        # 辅助变量
        self._a2l_file_path = a2l_file_path
        self._mearsurement_name_map: typing.Dict[str, XCPA2lMearsurement] = {}
        self._mearsurement_address_map: typing.Dict[int, XCPA2lMearsurement] = {}
        self._characteristic_name_map: typing.Dict[str, XCPA2lCharacteristic] = {}
        self._characteristic_address_map: typing.Dict[int, XCPA2lCharacteristic] = {}
        self._a2l_root: RootNodeType = None
        
        # 默认函数执行
        self._parser_a2l_file()
    
    def _parser_a2l_file(self) -> None:
        a2l_data = open(self._a2l_file_path, "rb").read()
        a2l_paser = A2lParser()
        self._a2l_root = a2l_paser.tree_from_a2l(a2l_data)
        mearsurements = self._a2l_root.PROJECT.MODULE[0].MEASUREMENT
        characteristics = self._a2l_root.PROJECT.MODULE[0].CHARACTERISTIC
        
        # 解析观测量
        for i in mearsurements:
            data_type:str = i.DataType.Value
            xcp_a2l_mearsurement = XCPA2lMearsurement(
                name=i.Name.Value,
                data_type=tool_function.MEARSUREMENT_DATATYPE_NAME_MAP_XCP_DATATYPE[data_type],
                address=i.ECU_ADDRESS.Address.Value
            )
            self._mearsurement_name_map[i.Name.Value] = xcp_a2l_mearsurement
            self._mearsurement_address_map[i.ECU_ADDRESS.Address.Value] = xcp_a2l_mearsurement
        
        # 解析标定量
        for i in characteristics:
            xcp_a2l_characteristic = XCPA2lCharacteristic(
                name=i.Name.Value,
                long_identifier=i.LongIdentifier.Value,
                record_layout=tool_function.CHARACTERISTIC_RECODER_LAYOUT_NAME_MAP_XCP_RECODER_LAYOUT[i.Deposit.Value],
                lower_limit=i.LowerLimit.Value,
                upper_limit=i.UpperLimit.Value,
                address=i.Address.Value,
            )
            self._characteristic_name_map[i.Name.Value] = xcp_a2l_characteristic
            self._characteristic_address_map[i.Address.Value] = xcp_a2l_characteristic
            
    
    def get_measurement_by_address(self, address:int) -> typing.Optional[XCPA2lMearsurement]:
        if (address not in self._mearsurement_address_map.keys()):
            return None
        return self._mearsurement_address_map[address]
        
    def get_characteristic_by_address(self, address:int) -> typing.Optional[XCPA2lCharacteristic]:
        if (address not in self._characteristic_address_map.keys()):
            return None
        return self._characteristic_address_map[address]
    
    def get_xcp_udp_port(self) -> int:
        port = self._a2l_root.PROJECT.MODULE[0].IF_DATA[0].Blob[4].Generic.Element[1].Long.Value
        return int(port)